#include <cstdlib>
#include <algorithm>
#include "rational.h"

int Rational::gcd(int a, int b) 
{
    if (a == b) {
        return a;    
    } else if (b < a) { 
        return gcd(b, a);        
    } else {
        return gcd(a, b - a);        
    }
}

void Rational::rationalize() 
{
    int divisor = gcd (abs(numerator), denominator);
    numerator /= divisor;
    denominator /= divisor;
}

void Rational::normalize() 
{
    if (denominator < 0) 
    {
        denominator = -denominator;
        numerator = -numerator;   
    }
}

Rational::Rational (int numerator, int denominator):
    numerator(numerator),
    denominator(denominator) 
{
    rationalize();
    normalize();
}

Rational::Rational (int integer):
    numerator(integer),
    denominator(1) 
{
}

Rational::Rational (const Rational& rat) :
		numerator (rat.numerator),
		denominator (rat.denominator)
{
}

Rational & Rational::operator = (const Rational& rat)
{
		numerator = rat.numerator;
		denominator = rat.denominator;
		return *this;
}

Rational & Rational::operator += (const Rational & r)
{
    numerator = numerator * r.denominator + r.numerator * denominator;
    denominator = denominator * r.denominator;
    rationalize();    
    return *this;
}

Rational & Rational::operator -= (const Rational & r)
{
    *this += -r;
    return *this;
}


Rational & Rational::operator *= (const Rational & r)
{
    numerator *= r.numerator;
    denominator *= r.denominator;
    rationalize();
    return *this;
}  

Rational & Rational::operator /= (const Rational & r)
{
    return *this *= r.inv();
}

Rational Rational::inv() const
{
    Rational result(*this);
    std::swap (result.numerator, result.denominator);
    result.normalize();
    return result;
}

Rational Rational::operator - () const 
{
    Rational result (-numerator, denominator);
    return result;
}

Rational & Rational::operator ++ () 
{
    return *this += 1;
}

Rational Rational::operator ++ (int) 
{
    Rational result = *this;
    ++(*this);
    return result;
}

Rational & Rational::operator -- ()
{
    return *this -= 1;
}

Rational Rational::operator -- (int)
{
    Rational result = *this;
    --(*this);
    return result;
}

bool operator == (const Rational & r1, const Rational & r2) 
{
    return r1.numerator == r2.numerator && r1.denominator == r2.denominator;
}
bool operator <= (const Rational & r1, const Rational & r2) 
{
    return !(r1 > r2);
}
bool operator >= (const Rational & r1, const Rational & r2) {
    return !(r1 < r2);
}
bool operator < (const Rational & r1, const Rational & r2) 
{
    return r1.numerator * r2.denominator < r2.numerator * r1.denominator;
}
bool operator > (const Rational & r1, const Rational & r2) 
{
    return r1 < r2;
}

Rational::operator double () const
{
    return numerator / (double) denominator;
}

Rational operator + (const Rational & r1, const Rational & r2)
{ 
    Rational result(r1);
    return result += r2;
}
Rational operator - (const Rational & r1, const Rational & r2) 
{
    Rational result(r1);
    return result -= r2;
}
Rational operator * (const Rational & r1, const Rational & r2) 
{
    Rational result(r1);
    return result *= r2;
}
Rational operator / (const Rational & r1, const Rational & r2) 
{
    Rational result(r1);
    return result /= r2;
}
